package controller

import (
	"bytes"
	"cn.pinming/gencode/core/logs"
	"cn.pinming/gencode/core/utils"
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"
)

func genByTemplate(table *Tableinfo, columnList *[]Columninfo, keyColumnList *[]Columninfo) {
	dir, _ := filepath.Abs("./")
	runlist := []rune(table.TableComment)
	if length := len(runlist); length == 0 {
		table.TableComment = table.TableName
	} else if length > 16 {
		table.TableComment = string(runlist[:16])
	}
	dir = dir + string(os.PathSeparator) + "uploads"
	outputRootDir := dir + string(os.PathSeparator) + "tmp"
	rootDir := dir + string(os.PathSeparator) + "templates"
	data := make(map[string]interface{})
	data["table"] = &table
	data["PascalName"] = utils.ToPascalName(table.TableName)
	data["CamelName"] = utils.ToCamelName(table.TableName)
	lowerName := utils.ToLowername(table.TableName)
	data["Lowername"] = lowerName
	data["columnList"] = columnList
	data["keyColumnList"] = keyColumnList
	var defaultIdColumnName string
	defaultIdColumnName = "id"
	if len(*keyColumnList) > 0 {
		defaultIdColumnName = (*keyColumnList)[0].PascalName
	}
	data["firstKeyColumn"] = defaultIdColumnName
	data["CreateTime"] = time.Now().Format("2006-01-02 15:04:05")
	cusMap := getTemplateConfig(rootDir)
	for key, value := range cusMap {
		if _, ok := data[key]; ok {
			logs.Debugf("数据键值已经存在（存在即抛弃原则）")
			continue
		}
		data[key] = value
	}
	fileList := getTemplateFileList(rootDir, rootDir, 0)
	for _, fileinfo := range fileList {
		genByTemplateEachFiles(table, outputRootDir, &fileinfo,
			lowerName, data)
	}
	logs.Debugf("模版生成成功，已可以下载。文件路径：", outputRootDir)
	//zip 打包并提供下载
}

func formatOutRelativePath(relativePath string, data map[string]interface{}) string {
	var result string
	result = relativePath
	result = strings.Replace(result, "${", "{{.", -1)
	result = strings.Replace(result, "}", "}}", -1)
	t, err := template.New("").Parse(result)
	if err != nil {
		logs.Error(err)
		return result
	}
	var b bytes.Buffer
	t.Execute(&b, data)
	tmp := b.String()
	if len(tmp) > 0 {
		result = tmp
	}
	result = strings.Replace(result, "{{.", "", -1)
	result = strings.Replace(result, "}}", "", -1)
	return result
}

func genByTemplateEachFiles(table *Tableinfo,
	outputRootDir string, fileinfo *TemplateFileInfo, lowerName string, data map[string]interface{}) {
	var funcMap = template.FuncMap{
		"upper": strings.ToUpper,
		"tosqltype": ToMapSqlDataType,
	}
	tpl := template.New(filepath.Base(fileinfo.Url))
	tpl.Funcs(funcMap)
	tpl, err := tpl.ParseFiles(fileinfo.Url)
	if err != nil {
		logs.Error(err)
		return
	}
	//以读写方式打开文件，如果不存在，则创建
	outputFileName := filepath.Join(outputRootDir, fileinfo.RelativePath, fileinfo.Filename)
	outputFileName = formatOutRelativePath(outputFileName, data)
	outputDir := filepath.Dir(outputFileName)
	_, err = os.Stat(outputDir)
	if err != nil {
		err = os.MkdirAll(outputDir, os.ModePerm)
		if err != nil {
			logs.Error(fmt.Sprintf("dir:%s error3:%s", outputDir, err))
		}
	}
	file2, err2 := os.OpenFile(outputFileName, os.O_RDWR|os.O_CREATE, 0766)
	if err2 != nil {
		logs.Error(err2)
		return
	}
	defer file2.Close()

	tpl.Execute(file2, data)
	msg := fmt.Sprintf("表：%s filename:%s 生成完毕", table.TableName, filepath.Join(fileinfo.RelativePath, fileinfo.Filename))
	logs.Debugf(msg)
}

func ToMapSqlDataType(dataType string) string {
	result := dataType
	switch dataType {
	case "time", "date", "datetime", "timestamp":
		result = "timestamp"
	}
	return strings.ToUpper(result)
}

func getTemplateConfig(rootPath string) map[string]interface{} {
	result := make(map[string]interface{})
	configPath := rootPath + string(os.PathSeparator) + "template.yml"
	_, err := os.Stat(configPath)
	if err != nil {
		logs.Debugf("模版配置文件为空不存在 %s", err)
		return result
	}
	configFile, err := ioutil.ReadFile(configPath)
	if err != nil {
		logs.Debugf("模版配置文件为空yamlFile.Get err %s ", err)
		return result
	}
	err = yaml.Unmarshal(configFile, result)
	if err != nil {
		logs.Errorf("模版配置文件解析失败 文件路径：%s 错误信息 %v ", err)
		return result
	}
	return result
}

/**
获取指定目录下的所有文件
*/
func getTemplateFileList(rootPath string, parentPath string, count int) (result []TemplateFileInfo) {
	if count > 9 {
		return
	}
	fileInfoList, _ := ioutil.ReadDir(parentPath)
	length := len(rootPath)
	for _, value := range fileInfoList {
		if value.IsDir() {
			parentPath := filepath.Join(parentPath, value.Name())
			list := getTemplateFileList(rootPath, parentPath, count+1)
			result = append(result, list...)
		} else {
			if count == 0 && strings.EqualFold(value.Name(), "template.yml") {
				continue
			}
			parentLength := len(parentPath)
			var dir string
			if length < parentLength {
				dir = parentPath[length:]
			}
			if strings.HasPrefix(dir, "/") {
				dir = dir[1:]
			}
			item := TemplateFileInfo{
				Url:          filepath.Join(parentPath, value.Name()),
				Ext:          filepath.Ext(value.Name()),
				Filename:     value.Name(),
				RelativePath: dir,
			}
			result = append(result, item)
		}
	}
	return result
}

type TemplateFileInfo struct {
	Url          string // 文件路径（/user/lfz/templates/test/test02/a.name）
	Filename     string // 文件名称(a.name)
	RelativePath string //相对路基  格式：test/test02/,不带开头字符串
	Ext          string
}
